/* ****************************************************************************
 *
 * Copyright 2013 informaticien77
 * 
 * This file is part of EasyCrypt - the AES and RSA implementation in C++.
 *
 * EasyCrypt is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * EasyCrypt is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with rsa.  If not, see <http://www.gnu.org/licenses/>.
 *
 * 				EasyCrypt.cpp
 * 
 * Author: informaticien77
 * Release date: 22th of May 2013
 * 
 * This file contains the implementation for the EasyCrypt class and the AES functions.
 * 
 * ****************************************************************************
 */

#define FULL_UNROLL

#include <string>
#include <sstream>
#include <time.h>
#include "EasyCrypt.h"
#include "KeyPair.h"
#include "Key.h"
#include "BigInt.h"
#include "RSA.h"
#include "MD5.h"

#define HASH_LEN 16

bool ec::RSA::GenerateKeys(unsigned long int digitCount, std::string *moduluskeys, std::string *privatexponent, std::string *publicexponent, unsigned long int precisionOfPrimality)
{
	std::srand(time(NULL));
	KeyPair kp = RSAH::GenerateKeyPair(digitCount, precisionOfPrimality);
	Key privatekey = kp.GetPrivateKey(), publickey = kp.GetPublicKey();
	BigInt privkmod = privatekey.GetModulus(), privkexp = privatekey.GetExponent(), publikmod = publickey.GetModulus(), publikexp = publickey.GetExponent();
	std::string privkmodt = privkmod.ToString(), privkexpt = privkexp, publikmodt = publikmod, publikexpt = publikexp;

	if(privkmodt == publikmodt){
		*moduluskeys = publikmodt;
		*privatexponent = privkexpt;
		*publicexponent = publikexpt;
		return true;
	}
	else{
		return false;
	}
}

std::string ec::RSA::Encrypt(std::string plaintext, std::string keymod, std::string keyexp)
{
	BigInt keymods = keymod, keyexps = keyexp;
	std::string encrypted = RSAH::Encrypt(plaintext, Key::Key(keymods, keyexps));
	return encrypted;
}

std::string ec::RSA::Decrypt(std::string cyphertext, std::string keymod, std::string keyexp)
{
	BigInt keymods = keymod, keyexps = keyexp;
	std::string decrypted ;
	try
	{
		decrypted=  RSAH::Decrypt(cyphertext, Key::Key(keymods, keyexps));

	}
	catch (char* pError)
	{	
		throw(pError);
	}

	return decrypted;
}

std::string ec::RSA::Digital_sign(std::string signtext, std::string keymod, std::string keyexp)
{
	unsigned char Outdigest[HASH_LEN];
	std::string Digest;
	memset(Outdigest, 0, sizeof(Outdigest));
	md5_digest(signtext.c_str(), signtext.size(), Outdigest);
	
	Digest.assign((char *)Outdigest, HASH_LEN);
	//memcpy(Digest.c_str(), Outdigest, HASH_LEN);
	return ec::RSA::Encrypt(Digest, keymod, keyexp);

}

bool ec::RSA::Sign_verify(std::string verifytext, std::string plaintext, std::string keymod, std::string keyexp)
{
	unsigned char En_digest[HASH_LEN];
	memset(En_digest, 0, sizeof(En_digest));
	std::string De_digest ;

	try
	{

		 De_digest = ec::RSA::Decrypt(verifytext, keymod, keyexp);


	}catch(char* pError)
	{
		return false;
	}
	
	md5_digest(plaintext.c_str(), plaintext.size(), En_digest);
	
	if (De_digest.size() == sizeof(En_digest)
		&& !memcmp(De_digest.c_str(), En_digest, sizeof(En_digest)))
	{
		return true;

	}
	return false;
}